package com.gitee.cirnochat.common.service.impl;


import cn.hutool.core.util.RandomUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.cirnochat.common.service.QrCodeService;
import com.gitee.cirnochat.common.utils.IpInfoUtil;
import com.gitee.cirnochat.common.utils.RequestUtils;
import com.gitee.cirnochat.login.model.dto.DeviceInfo;
import com.gitee.cirnochat.login.model.dto.LoginQrCodeStatus;
import com.gitee.cirnochat.login.model.entity.IprangeInfo;
import com.gitee.cirnochat.login.model.enums.DeviceType;
import com.gitee.cirnochat.login.model.enums.QrCodeStatus;
import com.gitee.cirnochat.login.model.enums.QrCodeType;
import com.gitee.cirnochat.login.model.vo.resp.LoginQrCodeStatusVo;
import com.gitee.cirnochat.login.service.IprangeInfoService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Set;

import static com.gitee.cirnochat.common.constant.QRCodeConstant.LOGIN_QR_CODE_EXPIRE_TIME;
import static com.gitee.cirnochat.common.constant.RedisKey.QR_CODE_ID_KEY;


@Service
@RequiredArgsConstructor
@Slf4j
public class QrCodeServiceImpl implements QrCodeService {
    private final IprangeInfoService iprangeInfoService;
    private final StringRedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    @Override
    public LoginQrCodeStatusVo generateLoginQrCode(HttpServletRequest request) {
        // 设备ID
        String deviceId = RequestUtils.getDeviceId(request);
        // 检查是否已有一个二维码信息
        Set<String> keys = redisTemplate.keys( QR_CODE_ID_KEY + String.format("%s#%d#*", deviceId, QrCodeType.LOGIN.getValue()));
        if (keys != null && !keys.isEmpty()) {
            String realKey = keys.iterator().next();
            String s = redisTemplate.opsForValue().get(realKey);
            LoginQrCodeStatusVo loginQrCodeStatus;
            try {
                loginQrCodeStatus = objectMapper.readValue(s, LoginQrCodeStatusVo.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            return loginQrCodeStatus;
        }
        // 二维码创建时间戳
        long createTime = System.currentTimeMillis();
        // 二维码过期时间戳
        long expireTime = createTime + LOGIN_QR_CODE_EXPIRE_TIME.toMillis();
        // 二维码ID
        String qrCodeId = RandomUtil.randomNumbers(10);
        // 设备信息
        String deviceName = RequestUtils.getDeviceName(request);
        DeviceType deviceType = DeviceType.fromValue(Integer.valueOf(RequestUtils.getDeviceType(request)));
        // IP位置信息
        String ipAddress = RequestUtils.getIp(request);
        IprangeInfo ip = iprangeInfoService.selectIpInfoByIpAddress(ipAddress);
        String location = IpInfoUtil.getIpLocation(ip);
        // 设置 Redis 中的二维码信息
        LoginQrCodeStatus loginQrCodeStatus = new LoginQrCodeStatus(qrCodeId, QrCodeStatus.PENDING, QrCodeType.LOGIN, new DeviceInfo(deviceName,deviceType), createTime, expireTime,location, null);
        try {
            redisTemplate.opsForValue().set(QR_CODE_ID_KEY + String.format("%s#%d#%s", deviceId, QrCodeType.LOGIN.getValue(), qrCodeId),
                    objectMapper.writeValueAsString(loginQrCodeStatus),
                    LOGIN_QR_CODE_EXPIRE_TIME);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return new LoginQrCodeStatusVo(loginQrCodeStatus);
    }

    @Override
    public LoginQrCodeStatusVo getLoginQrCodeStatus(String qrCodeId, HttpServletRequest request) {
        // 设备ID
        String deviceId = RequestUtils.getDeviceId(request);
        // 检查是否已有一个二维码信息
        String s = redisTemplate.opsForValue().get(QR_CODE_ID_KEY + String.format("%s#%d#%s", deviceId, QrCodeType.LOGIN.getValue(), qrCodeId));
        if (s != null ) {
            LoginQrCodeStatusVo loginQrCodeStatus;
            try {
                loginQrCodeStatus = objectMapper.readValue(s, LoginQrCodeStatusVo.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            return loginQrCodeStatus;
        } else {
            return new LoginQrCodeStatusVo(qrCodeId, QrCodeStatus.EXPIRED,QrCodeType.LOGIN);
        }
    }
}
